/**
 * Rename Subtitles. version 2.1
 */
package com.ai.business;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.stereotype.Component;

/**
 * @author jlijs
 *
 */
@Component
public class RenameAviToSrt {

    /**
     * constante para los videos
     */
    private static final String AVI = ".avi";
    /**
     * constante para los videos
     */
    private static final String MP4 = ".mp4";
    /**
     * constante para los videos
     */
    private static final String MKV = ".mkv";
    /**
     * constante para los subtitulos
     */
    private static final String SRT = ".srt";
    /**
     * se marca como procesado los que ya se renombraron.
     */
    private static final String PROCESADO = "procesado";

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        String nombreDirectorio = validarParametros(args);

        String[] filtrosVideos = {AVI, MP4, MKV};
        String[] filtrosSubs = {SRT};

        File[] archivosLeidosSrt = leerDirectorioConFiltro(nombreDirectorio, filtrosSubs);
        File[] archivosLeidosVideos = leerDirectorioConFiltro(nombreDirectorio, filtrosVideos);

        if (archivosLeidosVideos.length == 0) {
            System.out.println("No hay archivos de video (.avi o .mkv o .mp4) en el directorio, no se continua procesando.");
            throw new RuntimeException("No hay archivos de video (.avi o .mkv o .mp4) en el directorio, no se continua procesando.");
        }

        // chequeo que no sea pelicula. si es pelicula no normalizo el nombre del avi.
        if (archivosLeidosVideos[0].length() < 710000000 || archivosLeidosVideos.length > 2) {
            for (int i = 0; i < archivosLeidosVideos.length; i++) {
                String extensionArchivo = archivosLeidosVideos[i].getName().substring(archivosLeidosVideos[i].getName().length() - 4);
                String nombreNormalizado = normalizarNombreVideo(archivosLeidosVideos[i], extensionArchivo);
                String nombreViejo = archivosLeidosVideos[i].getAbsoluteFile().toString();
                if (!nombreViejo.equals(nombreNormalizado)) {
                    //cambio el nombre del archivo de video original, por el normalizado.
                    archivosLeidosVideos[i] = new File(nombreNormalizado);
                }
            }
        }

        compararArchivos(archivosLeidosVideos, archivosLeidosSrt);

    }

    /**
     * Valida los parametros y el directorio.
     *
     * @param args
     * @return
     */
    private static String validarParametros(String[] args) {
        if (args.length != 1) {
            System.out.println("Solo se permite un parametro de ejecucion.");
            throw new RuntimeException("Solo se permite un parametro de ejecucion.");
        }
        String nombreDirectorio = args[0];

        File directorio = new File(nombreDirectorio);
        if (!directorio.exists()) {
            System.out.println("Directorio inexistente: " + nombreDirectorio);
            throw new RuntimeException("Directorio inexistente: " + nombreDirectorio);
        }
        return nombreDirectorio;
    }

    /**
     * Se fija si el nombre del avi esta correcto, en minusculas y con la
     * temporada y capitulo en el formato: nombre.serie.101.avi
     *
     * @param archivoLeidoVideo avi a comprobar.
     */
    private static String normalizarNombreVideo(File archivoLeidoVideo, String extension) {
        String nombreArchivoARenombrar = archivoLeidoVideo.getName().toLowerCase();
        String pathOrigen = archivoLeidoVideo.getParent();
        String nombreArchivoRenombrado;
        Integer i = 0;

        StringTokenizer st = new StringTokenizer(nombreArchivoARenombrar, ".");
        StringBuffer armandoNombre = new StringBuffer();
        while (st.hasMoreTokens()) {
            i++;
            String nombreParseado = st.nextToken();
            // compilamos el patron
            Pattern patron = Pattern.compile("\\D");
            Matcher encaja = patron.matcher(nombreParseado);
            String comparacion = encaja.replaceAll("");
            //si el nombre del video empieza con un numero, lo dejo.
            if (i == 1) {
                armandoNombre.append(nombreParseado + ".");
                continue;
            }

            if (!comparacion.isEmpty()) {
                // saco los ceros a la izq.
                Long comparacionNumerica = Long.parseLong(comparacion);
                // si tiene algun anio se saca, si llegara a ser justo la temporada 20, tendria problemas...
                if (comparacionNumerica > 1980 && comparacionNumerica < 2020) {
                    continue;
                }
                comparacion = comparacionNumerica.toString();
                armandoNombre.append(comparacion + extension);
                break;
            } else {
                armandoNombre.append(nombreParseado + ".");
            }
        }

        nombreArchivoRenombrado = pathOrigen + "\\" + armandoNombre.toString();
        renombrarArchivo(archivoLeidoVideo, nombreArchivoRenombrado);

        return nombreArchivoRenombrado;
    }

    /**
     * va a comparar los avi con los srt para reemplazar los nombres.
     *
     * @param archivosLeidosVideo
     * @param archivosLeidosSrt
     * @throws IOException
     */
    private static void compararArchivos(File[] archivosLeidosVideo, File[] archivosLeidosSrt) throws IOException {
        // es 1 solo archivo reemplazo directo el srt con el nombre del avi.
        if (archivosLeidosVideo.length == 1 && archivosLeidosSrt.length == 1) {
            renombrarSubtitulos(archivosLeidosVideo[0], archivosLeidosSrt[0]);
        } else {
            // este seria para las series. (o mas de 1 archivo)
            compararSeries(archivosLeidosVideo, archivosLeidosSrt);
        }
    }

    /**
     * @param archivosLeidosAvi
     * @param archivosLeidosSrt
     * @throws IOException
     */
    private static void compararSeries(File[] archivosLeidosAvi, File[] archivosLeidosSrt) throws IOException {
        String aviAComparar;
        String srtAComparar;
        for (int i = 0; i < archivosLeidosAvi.length; i++) {
            //le saco la extension para comparar (en el caso de .mp4 rompia).
            aviAComparar = archivosLeidosAvi[i].getName().substring(0, archivosLeidosAvi[i].getName().length() - 4);

            // compilamos el patron
            Pattern patron = Pattern.compile("\\D");
            Matcher encajaAvi = patron.matcher(aviAComparar);
            // reemplazamos las letras por puntos, con esto separamos si hay numeros en el nombre del video.
            String comparacionAvi = encajaAvi.replaceAll(".");
            // nos quedamos con los ultimos numeros del nombre, que representarian la temporada y episodio.
            int posicion = comparacionAvi.lastIndexOf(".");
            comparacionAvi = comparacionAvi.substring(posicion + 1, comparacionAvi.length());

            if (!comparacionAvi.isEmpty()) {
                // saco los ceros a la izq.
                Long comparacionNumerica = Long.parseLong(comparacionAvi);
                comparacionAvi = comparacionNumerica.toString();
            } else { // dejo el nombre que tenia el avi.
                comparacionAvi = aviAComparar;
            }

            for (int j = 0; j < archivosLeidosSrt.length; j++) {
                srtAComparar = archivosLeidosSrt[j].getName();

                Matcher encajaSrt = patron.matcher(srtAComparar);
                String comparacionSrt = encajaSrt.replaceAll("");
                if (!comparacionSrt.isEmpty()) {
                    // saco los ceros a la izq.
                    Long comparacionNumerica = Long.parseLong(comparacionSrt);
                    comparacionSrt = comparacionNumerica.toString();
                } else { // dejo el nombre que tenia el avi.
                    comparacionSrt = srtAComparar;
                }

                if (!archivosLeidosSrt[j].getName().equals(PROCESADO)) {
                    if (comparacionSrt.contains(comparacionAvi)) {
                        renombrarSubtitulos(archivosLeidosAvi[i], archivosLeidosSrt[j]);
                        File a = new File(PROCESADO);
                        archivosLeidosSrt[j] = a;
                        break;
                    }
                }
            }
        }
    }

    /**
     * renombra el srt con el nombre del video.
     *
     * @param archivoLeidoVideo nombre del archivo a duplicar.
     * @param archivoLeidoSrt srt que tendra el mismo nombre que el video.
     * @throws IOException
     */
    private static void renombrarSubtitulos(File archivoLeidoVideo, File archivoLeidoSrt) throws IOException {
        String nombreArchivoARenombrar = archivoLeidoVideo.getName().substring(0, archivoLeidoVideo.getName().length() - 4);
        String pathOrigen = archivoLeidoSrt.getParent();
        String nombreArchivoRenombrado = pathOrigen + "\\" + nombreArchivoARenombrar + SRT;

        renombrarArchivo(archivoLeidoSrt, nombreArchivoRenombrado);
    }

    /**
     * Renombra el archivo con el nombre deseado.
     *
     * @param archivoARenombrar archivo al cual queremos renombrar.
     * @param nombreArchivoRenombrado nombre deseado que se le quiere poner.
     */
    private static void renombrarArchivo(File archivoARenombrar, String nombreArchivoRenombrado) {
        File archivoRenombrado = new File(nombreArchivoRenombrado);
        if (!nombreArchivoRenombrado.equals(archivoARenombrar.getAbsoluteFile().toString())) {
            boolean seRenombro = archivoARenombrar.renameTo(archivoRenombrado);
            if (seRenombro) {
                System.out.println("Archivo " + archivoARenombrar + " se renombro correctamente a: " + nombreArchivoRenombrado);
            } else {
                System.out.println("No se pudo renombrar el archivo: " + archivoARenombrar.getName());
            }
        } else {
            System.out.println("No hace falta renombrar el archivo: " + archivoARenombrar.getName());
        }
    }

    /**
     * Lee todos los archivos del directorio ingresado.
     *
     * @param nombreDirectorio directorio a leer.
     * @return archivos encontrados.
     */
    public static String[] leerDirectorio(String nombreDirectorio) {
        String path = nombreDirectorio;
        File directorio = new File(path);
        String[] ficheros = directorio.list();

        return ficheros;
    }

    /**
     * Lee los archivos del directorio ingresado que tengan el filtro pasado.
     *
     * @param nombreDirectorio nombre del directorio a scanear.
     * @param filtroArchivos filtros a buscar.
     * @return true si encontro el archivo con el filtro.
     * @throws IOException si hubo alguna exceptions.
     */
    public static File[] leerDirectorioConFiltro(String nombreDirectorio, final String[] filtroArchivos) throws IOException {
        File directorio = new File(nombreDirectorio);
        FileFilter filtrarArchivosPorExtension = new FileFilter() {
            Boolean esFiltro;

            public boolean accept(File file) {
                esFiltro = false;
                for (String filtro : filtroArchivos) {
                    if (file.getName().toLowerCase().endsWith(filtro)) {
                        esFiltro = true;
                    }
                }
                return esFiltro;
            }
        };
        File[] ficheros = directorio.listFiles(filtrarArchivosPorExtension);

        return ficheros;
    }
}
